﻿using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Authorization.Roles;
using Abp.Authorization.Users;
using Abp.Configuration;
using Abp.Domain.Repositories;
using Abp.EntityFrameworkCore.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.Notifications;
using Abp.Organizations;
using Abp.Runtime.Session;
using Abp.UI;
using Abp.Zero.Configuration;
using ARchGL.Platform.Application;
using ARchGL.Platform.Authorization.Permissions;
using ARchGL.Platform.Authorization.Permissions.Dto;
using ARchGL.Platform.Authorization.Roles;
using ARchGL.Platform.Authorization.Users.Dto;
using ARchGL.Platform.Authorization.Users.Exporting;
using ARchGL.Platform.Core;
using ARchGL.Platform.Dto;
using ARchGL.Platform.EntityFrameworkCore;
using ARchGL.Platform.Notifications;
using ARchGL.Platform.Organizations.Dto;
using ARchGL.Platform.Storage;
using ARchGL.Platform.Url;
using ARchGL.Platform.Utils;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;

namespace ARchGL.Platform.Authorization.Users
{
    /// <summary>
    /// 用户服务
    /// </summary>
#if !DEBUG
    [AbpAuthorize(AppPermissions.Pages_Administration_Users)]
#endif
    public class UserAppService : PlatformAppServiceBase, IUserAppService
    {
        public IAppUrlService AppUrlService { get; set; }

        private readonly RoleManager _roleManager;
        private readonly IUserEmailer _userEmailer;
        private readonly IUserListExcelExporter _userListExcelExporter;
        private readonly INotificationSubscriptionManager _notificationSubscriptionManager;
        private readonly IAppNotifier _appNotifier;
        private readonly IRepository<RolePermissionSetting, long> _rolePermissionRepository;
        private readonly IRepository<UserPermissionSetting, long> _userPermissionRepository;
        private readonly IRepository<UserRoleExtend, long> _userRoleRepository;
        private readonly IUserPolicy _userPolicy;
        private readonly IEnumerable<IPasswordValidator<User>> _passwordValidators;
        private readonly IPasswordHasher<User> _passwordHasher;
        private readonly IRepository<OrganizationUnit, long> organizationUnitRepository;
        private readonly IRepository<OrganizationUnitExtend, long> organizationUnitExtendRepository;
        private readonly IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository;
        private readonly IRepository<UserOrganizationUnitExtend, long> userOrganizationUnitExtendRepository;
        private readonly IRepository<User, long> usersRepository;
        private readonly IRepository<ProjectUsers, Guid> projectUserRepository;
        private readonly IRepository<Projects, Guid> projectsRepository;
        private readonly IBinaryObjectManager _binaryObjectManager;
        public UserAppService(
            RoleManager roleManager,
            IUserEmailer userEmailer,
            IUserListExcelExporter userListExcelExporter,
            INotificationSubscriptionManager notificationSubscriptionManager,
            IAppNotifier appNotifier,
            IRepository<RolePermissionSetting, long> rolePermissionRepository,
            IRepository<UserPermissionSetting, long> userPermissionRepository,
            IRepository<UserRoleExtend, long> userRoleRepository,
            IUserPolicy userPolicy,
            IEnumerable<IPasswordValidator<User>> passwordValidators,
            IPasswordHasher<User> passwordHasher,
            IRepository<OrganizationUnit, long> _organizationUnitRepository,
            IRepository<OrganizationUnitExtend, long> _organizationUnitExtendRepository,
            IRepository<UserOrganizationUnit, long> _userOrganizationUnitRepository,
            IRepository<UserOrganizationUnitExtend, long> _userOrganizationUnitExtendRepository,
            IRepository<User, long> _usersRepository,
            IRepository<ProjectUsers, Guid> _projectUserRepository,
            IRepository<Projects, Guid> _projectsRepository,
               IBinaryObjectManager binaryObjectManager)
        {
            _roleManager = roleManager;
            _userEmailer = userEmailer;
            _userListExcelExporter = userListExcelExporter;
            _notificationSubscriptionManager = notificationSubscriptionManager;
            _appNotifier = appNotifier;
            _rolePermissionRepository = rolePermissionRepository;
            _userPermissionRepository = userPermissionRepository;
            _userRoleRepository = userRoleRepository;
            _userPolicy = userPolicy;
            _passwordValidators = passwordValidators;
            _passwordHasher = passwordHasher;
            organizationUnitRepository = _organizationUnitRepository;
            organizationUnitExtendRepository = _organizationUnitExtendRepository;
            userOrganizationUnitRepository = _userOrganizationUnitRepository;
            userOrganizationUnitExtendRepository = _userOrganizationUnitExtendRepository;
            usersRepository = _usersRepository;
            projectUserRepository = _projectUserRepository;
            AppUrlService = NullAppUrlService.Instance;
            projectsRepository = _projectsRepository;
            _binaryObjectManager = binaryObjectManager;
        }

        /// <summary>
        /// 获取用户集合
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<UserListDto>> GetUsers(GetUsersInput input)
        {
            var query = UserManager.Users
                .WhereIf(input.Role.HasValue, u => u.Roles.Any(r => r.RoleId == input.Role.Value))
                .WhereIf(input.OnlyLockedUsers, u => u.LockoutEndDateUtc.HasValue && u.LockoutEndDateUtc.Value > DateTime.UtcNow)
                .WhereIf(!input.Filter.IsNullOrWhiteSpace(), u =>
                        u.Name.Contains(input.Filter) ||
                        u.Surname.Contains(input.Filter) ||
                        u.UserName.Contains(input.Filter) ||
                        u.PhoneNumber.Contains(input.Filter) ||
                        u.EmailAddress.Contains(input.Filter)
                );

            if (!input.Permission.IsNullOrWhiteSpace())
            {
                query = from user in query
                        join ur in _userRoleRepository.GetAll() on user.Id equals ur.UserId into urJoined
                        from ur in urJoined.DefaultIfEmpty()
                        join up in _userPermissionRepository.GetAll() on new { UserId = user.Id, Name = input.Permission } equals new { up.UserId, up.Name } into upJoined
                        from up in upJoined.DefaultIfEmpty()
                        join rp in _rolePermissionRepository.GetAll() on new { RoleId = ur == null ? 0 : ur.RoleId, Name = input.Permission } equals new { rp.RoleId, rp.Name } into rpJoined
                        from rp in rpJoined.DefaultIfEmpty()
                        where up != null && up.IsGranted || up == null && rp != null
                        group user by user
                        into userGrouped
                        select userGrouped.Key;
            }
            var userCount = await query.CountAsync();

            var users = await query
                .OrderBy(input.Sorting)
                .PageByAsync(input);

            var userListDtos = ObjectMapper.Map<List<UserListDto>>(users);

            #region 部门信息赋值

            var organizationUnitQuery = from user in users
                                        join uou in userOrganizationUnitRepository.GetAll() on user.Id equals uou.UserId
                                        //into uouJoined
                                        //from uou in uouJoined.DefaultIfEmpty()
                                        join ou in organizationUnitRepository.GetAll() on uou.OrganizationUnitId equals ou.Id
                                        //into ouJoined
                                        //from ou in ouJoined.DefaultIfEmpty()
                                        select new
                                        {
                                            UserId = user.Id,
                                            uou.OrganizationUnitId,
                                            ou.Code,
                                            ou.DisplayName
                                        };

            foreach (var item in userListDtos)
            {
                try
                {
                    var entity = organizationUnitQuery.OrderByDescending(t => t.Code).FirstOrDefault(x => x.UserId == item.Id);
                    if (entity != null)
                    {
                        item.OrganizationUnitId = entity.OrganizationUnitId;
                        item.OrganizationUnitName = entity.DisplayName;
                    }
                }
                catch
                {
                    continue;
                }
            }

            #endregion

            await FillRoleNames(userListDtos);

            return new PagedResultDto<UserListDto>(
                userCount,
                userListDtos
                );
        }

        public async Task<FileDto> GetUsersToExcel()
        {
            var users = await UserManager.Users.ToListAsync();
            var userListDtos = ObjectMapper.Map<List<UserListDto>>(users);
            await FillRoleNames(userListDtos);

            return _userListExcelExporter.ExportToFile(userListDtos);
        }

        public async Task<GetUserForEditOutput> GetUserForEdit(NullableIdDto<long> input)
        {
            //Getting all available roles
            var userRoleDtos = await _roleManager.Roles
                .OrderBy(r => r.DisplayName)
                .Select(r => new UserRoleDto
                {
                    RoleId = r.Id,
                    RoleName = r.Name,
                    RoleDisplayName = r.DisplayName
                })
                .ToArrayAsync();

            var allOrganizationUnits = await organizationUnitRepository.GetAllListAsync();

            var output = new GetUserForEditOutput
            {
                Roles = userRoleDtos,
                AllOrganizationUnits = ObjectMapper.Map<List<OrganizationUnitDto>>(allOrganizationUnits),
                MemberedOrganizationUnits = new List<string>()
            };

            if (!input.Id.HasValue)
            {
                //Creating a new user
                output.User = new UserEditDto
                {
                    IsActive = true,
                    ShouldChangePasswordOnNextLogin = true,
                    IsTwoFactorEnabled = await SettingManager.GetSettingValueAsync<bool>(AbpZeroSettingNames.UserManagement.TwoFactorLogin.IsEnabled),
                    IsLockoutEnabled = await SettingManager.GetSettingValueAsync<bool>(AbpZeroSettingNames.UserManagement.UserLockOut.IsEnabled)
                };

                foreach (var defaultRole in await _roleManager.Roles.Where(r => r.IsDefault).ToListAsync())
                {
                    var defaultUserRole = userRoleDtos.FirstOrDefault(ur => ur.RoleName == defaultRole.Name);
                    if (defaultUserRole != null)
                    {
                        defaultUserRole.IsAssigned = true;
                    }
                }
            }
            else
            {
                //Editing an existing user
                var user = await UserManager.GetUserByIdAsync(input.Id.Value);

                output.User = ObjectMapper.Map<UserEditDto>(user);
                output.ProfilePictureId = user.ProfilePictureId;

                foreach (var userRoleDto in userRoleDtos)
                {
                    userRoleDto.IsAssigned = await UserManager.IsInRoleAsync(user, userRoleDto.RoleName);
                }

                var organizationUnits = await UserManager.GetOrganizationUnitsAsync(user);
                output.MemberedOrganizationUnits = organizationUnits.Select(ou => ou.Code).ToList();

                //头像
                try
                {
                    var bytes = await GetProfilePictureByIdOrNull(output.ProfilePictureId.Value);
                    output.ProfilePicture = bytes == null ? "" : Convert.ToBase64String(bytes);
                }
                catch
                {
                }
                //output.User.OrganizationUnitName = organizationUnits.LastOrDefault()?.DisplayName; //部门名称
            }

            return output;
        }

        /// <summary>
        /// 根据用户标识获取用户信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<object> GetUserById(EntityDto<Guid> input)
        {
            var user = await UserManager.Users.FirstOrDefaultAsync(x => x.PrimaryId == input.Id);
            if (user == null) throw new UserFriendlyException("用户不存在，请重新输入");

            var organizationUnits = await UserManager.GetOrganizationUnitsAsync(user);

            return new
            {
                //数组中第一个是部门，最后一个是公司
                MemberedOrganizationUnits = organizationUnits.Select(x => x.DisplayName).ToList(),
                user.Name,
                user.Avatar,
                user.EmailAddress,
                user.PhoneNumber,
                user.Gender,
            };
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_Users_ChangePermissions)]
        public async Task<GetUserPermissionsForEditOutput> GetUserPermissionsForEdit(EntityDto<long> input)
        {
            var user = await UserManager.GetUserByIdAsync(input.Id);
            var permissions = PermissionManager.GetAllPermissions();
            var grantedPermissions = await UserManager.GetGrantedPermissionsAsync(user);

            return new GetUserPermissionsForEditOutput
            {
                Permissions = ObjectMapper.Map<List<FlatPermissionDto>>(permissions).OrderBy(p => p.DisplayName).ToList(),
                GrantedPermissionNames = grantedPermissions.Select(p => p.Name).ToList()
            };
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_Users_ChangePermissions)]
        public async Task ResetUserSpecificPermissions(EntityDto<long> input)
        {
            var user = await UserManager.GetUserByIdAsync(input.Id);
            await UserManager.ResetAllPermissionsAsync(user);
        }

        /// <summary>
        /// 更新用户权限
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AbpAuthorize(AppPermissions.Pages_Administration_Users_ChangePermissions)]
        public async Task UpdateUserPermissions(UpdateUserPermissionsInput input)
        {
            var user = await UserManager.GetUserByIdAsync(input.Id);
            var grantedPermissions = PermissionManager.GetPermissionsFromNamesByValidating(input.GrantedPermissionNames);
            await UserManager.SetGrantedPermissionsAsync(user, grantedPermissions);
        }

        /// <summary>
        /// 创建或更新用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<long> CreateOrUpdateUser(CreateOrUpdateUserInput input)
        {
            if (!input.User.Password.IsNullOrWhiteSpace() && input.User.Password.Length < 32)
                input.User.Password = input.User.Password.ToMd5();

            input.User.UserName = input.User.UserName.Replace("\t", "")?.ToLowerInvariant();
            User user = null;

            if (input.User.Id.HasValue)
            {
                user = await UpdateUserAsync(input);
            }
            else
            {
                user = await CreateUserAsync(input);
            }
            await UpdateUserExtendInfo(user);
            return user.Id;
        }

        /// <summary>
        /// 删除用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AbpAuthorize(AppPermissions.Pages_Administration_Users_Delete)]
        public async Task DeleteUser(EntityDto<long> input)
        {
            if (input.Id == AbpSession.GetUserId())
            {
                throw new UserFriendlyException(L("YouCanNotDeleteOwnAccount"));
            }

            var user = await UserManager.GetUserByIdAsync(input.Id);
            StaticUserIds.CheckIsSystemInfo(user.PrimaryId); //检查是否系统用户

            if (projectsRepository.Count(p => p.CreatorUserId.HasValue && p.CreatorUserId == user.PrimaryId) > 0)
                throw new UserFriendlyException("当前用户名下有活动项目，请先删除相关项目");

            CheckErrors(await UserManager.DeleteAsync(user));

            await projectUserRepository.RemoveUserOnProjectByUserId(user.PrimaryId);
        }

        /// <summary>
        /// 批量删除用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AbpAuthorize(AppPermissions.Pages_Administration_Users_Delete)]
        public async Task BatchDeleteUser(List<long> input)
        {
            var list = await UserManager.Users.Where(x => input.Contains(x.Id) && x.Id != AbpSession.GetUserId()).ToListAsync();
            foreach (var item in list)
            {
                StaticUserIds.CheckIsSystemInfo(item.PrimaryId);
                CheckErrors(await UserManager.DeleteAsync(item));
            }
        }

        /// <summary>
        /// 解除锁定
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UnlockUser(EntityDto<long> input)
        {
            var user = await UserManager.GetUserByIdAsync(input.Id);
            user.Unlock();
        }

        /// <summary>
        /// 更新激活状态，根据当前状态反转
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task UpdateActiveStatus(long userId)
        {
            var entity = await UserManager.Users.FirstOrDefaultAsync(x => x.Id == userId);
            if (entity == null) throw new UserFriendlyException(L("TheUserDoesNotExist"), L("PleaseRefreshThePageAndTryAgain"));
            if (entity.UserName == User.AdminUserName) throw new UserFriendlyException(L("SystemAccountCannotBeDisabled"));

            entity.IsActive = !entity.IsActive;
            await UserManager.UpdateAsync(entity);
        }

        /// <summary>
        /// 更新用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
#if !DEBUG
        [AbpAuthorize(AppPermissions.Pages_Administration_Users_Edit)]
#endif
        protected virtual async Task<User> UpdateUserAsync(CreateOrUpdateUserInput input)
        {
            Debug.Assert(input.User.Id != null, "input.User.Id should be set.");

            var user = await UserManager.FindByIdAsync(input.User.Id.Value.ToString());
            user.CheckType();

            //Update user properties
            var type = user.Type;
            ObjectMapper.Map(input.User, user); //Passwords is not mapped (see mapping configuration)
            user.Type = type;

            var organizationUnitList = await organizationUnitRepository.GetAll().Select(x => x.Id)
                        .Where(x => input.OrganizationUnits.Contains(x)).ToListAsync();
            foreach (var item in input.OrganizationUnits)
            {
                if (item != 0 && !organizationUnitList.Contains(item))
                    throw new UserFriendlyException("部门不存在，请重新输入");
            }

            if (!input.User.Password.IsNullOrWhiteSpace() && input.User.Password.Length < 32)
                input.User.Password = input.User.Password.ToMd5();

            if (input.SetRandomPassword)
            {
                user.Password = _passwordHasher.HashPassword(user, User.CreateRandomPassword());
            }
            else if (!input.User.Password.IsNullOrEmpty())
            {
                await UserManager.InitializeOptionsAsync(AbpSession.TenantId);
                CheckErrors(await UserManager.ChangePasswordAsync(user, input.User.Password));
            }

            CheckErrors(await UserManager.UpdateAsync(user));

            //Update roles
            CheckErrors(await UserManager.SetRoles(user, input.AssignedRoleNames));

            //update organization units
            await SetOrganizationUnitsAsync(user, input.OrganizationUnits.ToArray());

            if (input.SendActivationEmail)
            {
                user.SetNewEmailConfirmationCode();
                await _userEmailer.SendEmailActivationLinkAsync(
                    user,
                    AppUrlService.CreateEmailActivationUrlFormat(AbpSession.TenantId),
                    input.User.Password
                );
            }
            return user;
        }

        protected virtual async Task SetOrganizationUnitsAsync(User user, params long[] organizationUnitIds)
        {
            if (organizationUnitIds == null) organizationUnitIds = new long[0];
            var currentOus = await UserManager.GetOrganizationUnitsAsync(user);

            //Remove from removed OUs
            foreach (var currentOu in currentOus)
            {
                if (!organizationUnitIds.Contains(currentOu.Id))
                {
                    await userOrganizationUnitRepository.DeleteAsync(uou => uou.UserId == user.Id && uou.OrganizationUnitId == currentOu.Id);
                }
            }

            //Add to added OUs
            foreach (var organizationUnitId in organizationUnitIds)
            {
                if (currentOus.All(ou => ou.Id != organizationUnitId))
                {
                    await AddToOrganizationUnitAsync(
                        user,
                        await organizationUnitExtendRepository.GetAsync(organizationUnitId)
                        );
                }
            }
        }

        protected virtual async Task AddToOrganizationUnitAsync(User user, OrganizationUnitExtend ou)
        {
            var currentOus = await UserManager.GetOrganizationUnitsAsync(user);
            if (currentOus.Any(cou => cou.Id == ou.Id)) return;

            await userOrganizationUnitExtendRepository.InsertAsync(new UserOrganizationUnitExtend(user.TenantId, user, ou));
        }

        /// <summary>
        /// 创建用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
#if !DEBUG
        [AbpAuthorize(AppPermissions.Pages_Administration_Users_Create)]
#endif
        protected virtual async Task<User> CreateUserAsync(CreateOrUpdateUserInput input)
        {
            if (AbpSession.TenantId.HasValue)
            {
                await _userPolicy.CheckMaxUserCountAsync(AbpSession.GetTenantId());
            }

            input.User.UserName = input.User.UserName.Trim().Replace("\t", "");
#if !DEBUG
            var entity = await usersRepository.FirstOrDefaultAsync(x => x.PhoneNumber == input.User.PhoneNumber);
            if (entity != null) throw new UserFriendlyException("该手机号已存在，请重新输入");

            entity = await usersRepository.FirstOrDefaultAsync(x => x.UserName == input.User.UserName);
            if (entity != null) throw new UserFriendlyException("该帐号已存在，请重新输入");
#endif
            var user = ObjectMapper.Map<User>(input.User); //Passwords is not mapped (see mapping configuration)
            user.TenantId = AbpSession.TenantId;
            user.PrimaryId = GuidGenerator.Create();
            if (input.User.Type == 0) user.Type = UserType.一般租户;
            else user.Type = input.User.Type;

            if (!input.User.Password.IsNullOrWhiteSpace() && input.User.Password.Length < 32)
                input.User.Password = input.User.Password.ToMd5();

            if (input.User.Password.IsNullOrEmpty())//密码为空时，自动设置和帐号一样
                input.User.Password = input.User.UserName.ToMd5();

            //Set password
            if (input.SetRandomPassword)
            {
                user.Password = _passwordHasher.HashPassword(user, User.CreateRandomPassword());
            }
            else if (!input.User.Password.IsNullOrEmpty())
            {
                await UserManager.InitializeOptionsAsync(AbpSession.TenantId);
                //foreach (var validator in _passwordValidators)
                //{
                //    CheckErrors(await validator.ValidateAsync(UserManager, user, input.User.Password));
                //}
                user.Password = _passwordHasher.HashPassword(user, input.User.Password);
            }

            user.ShouldChangePasswordOnNextLogin = input.User.ShouldChangePasswordOnNextLogin;

            //Assign roles
            user.Roles = new Collection<UserRole>();
            foreach (var roleName in input.AssignedRoleNames)
            {
                var role = await _roleManager.GetRoleByNameAsync(roleName);
                user.Roles.Add(new UserRole(AbpSession.TenantId, user.Id, role.Id));
            }

            CheckErrors(await UserManager.CreateAsync(user));
            await CurrentUnitOfWork.SaveChangesAsync(); //To get new user's Id.

            //Notifications
            await _notificationSubscriptionManager.SubscribeToAllAvailableNotificationsAsync(user.ToUserIdentifier());
            await _appNotifier.WelcomeToTheApplicationAsync(user);

            //Organization Units
            await SetOrganizationUnitsAsync(user, input.OrganizationUnits.ToArray());

            //Send activation email
            if (input.SendActivationEmail)
            {
                user.SetNewEmailConfirmationCode();
                await _userEmailer.SendEmailActivationLinkAsync(
                    user,
                    AppUrlService.CreateEmailActivationUrlFormat(AbpSession.TenantId),
                    input.User.Password
                );
            }
            return user;
        }

        /// <summary>
        /// 创建用户成功后更新角色用户中间表扩展信息
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        private async Task UpdateUserExtendInfo(User user)
        {
            var dbContext = _userRoleRepository.GetDbContext();
            var sql = $"UPDATE \"AbpUserRoles\" SET Discriminator=@UserRoleExtend WHERE Discriminator!=@UserRoleExtend";
            dbContext.Execute(sql, nameof(UserRoleExtend), nameof(UserRoleExtend));

            sql = $"UPDATE \"AbpUserRoles\" SET UserPrimaryId=@PrimaryId WHERE UserId=@UserId AND UserPrimaryId IS NULL";
            dbContext.Execute(sql, user.PrimaryId, user.Id);
        }

        /// <summary>
        /// 拼接用户角色名称
        /// </summary>
        /// <param name="userListDtos"></param>
        /// <returns></returns>
        private async Task FillRoleNames(List<UserListDto> userListDtos)
        {
            /* This method is optimized to fill role names to given list. */

            var userRoles = await _userRoleRepository.GetAll()
                .Where(userRole => userListDtos.Any(user => user.Id == userRole.UserId))
                .Select(userRole => userRole).ToListAsync();

            var distinctRoleIds = userRoles.Select(userRole => userRole.RoleId).Distinct();

            foreach (var user in userListDtos)
            {
                var rolesOfUser = userRoles.Where(userRole => userRole.UserId == user.Id).ToList();
                user.Roles = ObjectMapper.Map<List<UserListRoleDto>>(rolesOfUser);
            }

            var roleNames = new Dictionary<int, dynamic>();
            foreach (var roleId in distinctRoleIds)
            {
                var entity = await _roleManager.GetRoleByIdAsync(roleId);
                roleNames[roleId] = new[] { entity.DisplayName, entity.Name };
            }

            foreach (var userListDto in userListDtos)
            {
                foreach (var userListRoleDto in userListDto.Roles)
                {
                    userListRoleDto.DisplayName = roleNames[userListRoleDto.RoleId][0];
                    userListRoleDto.Name = roleNames[userListRoleDto.RoleId][1];
                }

                userListDto.Roles = userListDto.Roles.OrderBy(r => r.DisplayName).ToList();
            }
        }

        private async Task<byte[]> GetProfilePictureByIdOrNull(Guid profilePictureId)
        {
            var file = await _binaryObjectManager.GetOrNullAsync(profilePictureId);
            if (file == null)
            {
                return null;
            }

            return file.Bytes;
        }
    }
}
